/*
 * ゲームマネージャ (game.c)
 */
#include <system.h>
#include <v93.h>
#include <vpsg.h>
#include <libm.h>
#include <intlib.h>
#include <farl.h>
#include "spec.h"
#include "funcdecl.h"
#include "vardecl.h"
#include "service.h"
#include "psgdef.h"
#include "math.h"

#ifndef LOCAL
#define LOCAL
#endif

#define STRLENGTH   (8)		/* "BULLYOFF"の文字数 */
/* 背景は 180°で 256 ドットまわる。 */
#define DEGPERDOTS  (256.0 / 180.0)

/*
  ----------------------------------------
  ローカル変数
  ----------------------------------------
  */
LOCAL int gameTimer;                        /* 残り時間 */
LOCAL struct object obj[8];                 
LOCAL int iRotateAngle;                     /* タイトルアクション時カウンタ */
LOCAL int iFontColor;                       /* タイトルフォント色 */
LOCAL unsigned short BullyXRot[STRLENGTH];  /* タイトルフォントの横回転の度合*/
LOCAL unsigned short BullySize[STRLENGTH];  /* タイトルフォントの拡大率 */
LOCAL unsigned short BullyZSize[STRLENGTH]; /* タイトルフォントの縦の拡大率 */
LOCAL float BullyYPos[STRLENGTH];           /* タイトルフォントの縦位置 */
LOCAL float BullyXPos[STRLENGTH] = {        /* タイトルフォントの横位置 */
      -0.24,    /* b */
      -0.17,    /* u */
      -0.105,   /* l */
      -0.045,   /* l */
       0.018,   /* y */
       0.110,   /* o */
       0.180,   /* f */
       0.245,   /* f */
       };
/* テクスチャ、ADPCM データを読み込んだかどうかのフラグ: This is dirty flag */
LOCAL int alreadyRead = FALSE;
LOCAL Material BullyMaterial;               /* タイトルフォントのマテリアル */

/* 
----------------------------------------
  ローカル関数
----------------------------------------
*/
LOCAL void FontInit(void);                  /* フォント初期化 */
LOCAL void FontMove(void);                  /* フォント移動 */
LOCAL void SetDefaultCar(int round);        /* 機体パラメータ設定 */

/* 
----------------------------------------
  VSCOM 時のオブジェクト設定
----------------------------------------
*/
enum {
  ORDER0,                        /* 自機 */
  ORDER1,
  ORDER2,
  ORDER3,
  ORDER_MAX,
};

#define START_ROUND (1)                /* 開始ラウンド */
#define BOSS_ROUND (3)                /* ボス登場ラウンド */

typedef struct {
  unsigned short *obj;
  long len;
  float width;
  float h_plus;
  float h_minus;
} machOrder;
LOCAL machOrder order[ORDER_MAX]; /* 3 round */

/* 
----------------------------------------
  ラウンドに対応した機体を選択する
  最終面はボスのテクスチャをファイルから
  読み込み、設定する
  ここに書いてある 03,04,05以外にも
  車のデータがあるのでそれを組み込んで
  見てください。
  車を変える時は、選択画面でも変わるように
  select.c の中も変えるようにしてください。
  また、テクスチャーデータも変更しなければ
  なりません。ResetGame内の
  ReadTexture で読み込むファイルを変更
  してください。
----------------------------------------
*/
LOCAL void
SetDefaultCar(int round)
{
  float scale = FarlFloat187(SCALE_CAR) * OBJ_SCALE / 0.8;

  if (round == ORDER1) {
    /* 
     * ラウンドの最初でいろいろ初期化をする
     */
    order[ORDER0].obj     = obj05_g;
    order[ORDER0].len     = obj05_g_length / sizeof(int);
    order[ORDER0].width   = ( FarlFloat1015(obj05_minmax[MAXX]) / scale) * 0.2;
    order[ORDER0].h_plus  = FarlFloat1015(obj05_minmax[MAXZ]) / scale;
    order[ORDER0].h_minus = FarlFloat1015(obj05_minmax[MINZ]) / scale;
    /* round 1 */
    order[ORDER1].obj     = obj03_g;
    order[ORDER1].len     = obj03_g_length / sizeof(int);
    order[ORDER1].width   = ( FarlFloat1015(obj03_minmax[MAXX]) / scale) * 0.2;
    order[ORDER1].h_plus  = FarlFloat1015(obj03_minmax[MAXZ]) / scale;
    order[ORDER1].h_minus = FarlFloat1015(obj03_minmax[MINZ]) / scale;
    /* round 2 */
    order[ORDER2].obj     = obj04_g;
    order[ORDER2].len     = obj04_g_length / sizeof(int);
    order[ORDER2].width   = ( FarlFloat1015(obj04_minmax[MAXX]) / scale) * 0.2;
    order[ORDER2].h_plus  = FarlFloat1015(obj04_minmax[MAXZ]) / scale;
    order[ORDER2].h_minus = FarlFloat1015(obj04_minmax[MINZ]) / scale;
    /* round 3 */
    order[ORDER3].obj     = boss_g;
    order[ORDER3].len     = boss_g_length / sizeof(int);
    order[ORDER3].width   = ( FarlFloat1015(boss_minmax[MAXX]) / scale);
    order[ORDER3].h_plus  = FarlFloat1015(boss_minmax[MAXZ]) / scale;
    order[ORDER3].h_minus = FarlFloat1015(boss_minmax[MINZ]) / scale;

    /* 1P object */
    machPlayer1 = PLAYER_DUMMY;
    Machine[PLAYER1].type->obj.geometryTop = (int *)order[ORDER0].obj;
    Machine[PLAYER1].type->obj.geometryLength = order[ORDER0].len;
    Machine[PLAYER1].type->width = order[ORDER0].width;
    Machine[PLAYER1].type->h_plus = order[ORDER0].h_plus;
    Machine[PLAYER1].type->h_minus = order[ORDER0].h_minus;
    Machine[PLAYER1].type->obj.material = &aMaterial[PLAYER1];
  }
  if (round == BOSS_ROUND) {
    KINGScreen(1);
    KINGCls(KING_BG0);
    KINGScroll(KING_BG0, 0, 0);
    NowLoading();
    dispon(bg0 | bg | spr);
    ReadTexture(FALSE, "dat/cartex/boss.aid", TBANK_P3); /* ボス車テクスチャ */
    SetTextureBank(boss_g, boss_g_tindex, TBANK_P3);
  }
  /* 2P object */
  machPlayer2 = round;
  Machine[PLAYER2].type->obj.geometryTop = (int *)order[round].obj;
  Machine[PLAYER2].type->obj.geometryLength = order[round].len;
  Machine[PLAYER2].type->obj.material = &aMaterial[PLAYER2];
  Machine[PLAYER2].type->width = order[round].width;
  Machine[PLAYER2].type->h_plus = order[round].h_plus;
  Machine[PLAYER2].type->h_minus = order[round].h_minus;
}

/*
----------------------------------------
  タイマー減算
----------------------------------------
*/
LOCAL void
TimerDecrement()
{
  static int timer = 0;

  timer++;
  if (timer >= 60) {
    timer = 0;
    gameTimer--;
  }
}

/*
========================================
  残り時間を得る
========================================
*/
time_t
GetRestTime()
{
  return gameTimer;
}

/*
========================================
  0-65535の擬似乱数を返す
========================================
*/
int
random()
{
  static int seed = 7;

  seed = 13 * seed + 31;
  return seed % 65536;
}

/*
----------------------------------------
  モード設定

  Opening() から呼ばれる
----------------------------------------
*/
LOCAL void
SelectGame()
{
  dispon(bg | spr);
  playmode = VSCOM;
  FontInit();

  /* パッドから入力 */
  get_pad();
  /* run が押されたら終了 */
  while (1) {
    VSyncWait();
    /* RUNか 1が押されたら抜ける */
    get_pad();
    if ((pad00.KD_TRG & KP_run) || (pad00.KD_TRG & KP_1))
      break;
    /* 上か下が押されたらモードを変えて音をならす */
    if ((pad00.KD_TRG & KP_up) || (pad00.KD_TRG & KP_down)) {
      playmode = (playmode == VSCOM) ? VSPLAYER : VSCOM;
      PSGSeOn(SE_CURMOVE);
    }
    /* フォントを動かす */
    FontMove();
    /* カーソルを表示する */
    CurPut(64, 162 + ((playmode == VSCOM) ? 0 : 18));
    /* 表示終了まで待つ */
    ASLSync();
    AGLShot();
    MSLSync();
  }
  /* 決定音をならしてカーソルを消す */
  PSGSeOn(SE_CURSEL);
  CurErase();
}

/*
----------------------------------------
  ゲームオープニング
----------------------------------------
*/
LOCAL void
Opening()
{
  playmode_t pmPlaymode;
  
  /* ＰＣＭの初期化 */
  AdpcmVolume(CHANNEL_1, MIN_PCM_VOLUME, MIN_PCM_VOLUME);
  AdpcmVolume(CHANNEL_2, MIN_PCM_VOLUME, MIN_PCM_VOLUME);
  AdpcmInit();
  AdpcmVolume(CHANNEL_1, MAX_PCM_VOLUME, MAX_PCM_VOLUME);

  /* 周辺初期化 */
  DevInit();
  UserInitDev();
  /* スクロールレジスタの初期化 */
  KINGScroll(KING_BG0, 0, 0);
  /* ＰＳＧを止める */
  PSGClear();
  /* 表示オフ */
  dispoff(bg | spr | bg0);
  KINGDispOff();
  /* Ｃ６２７２画面設定 */
  KINGScreen(1);
  KINGChangeSize0(DISP_NORMAL);
  KINGKanjiMode(PSET, YUV_WHITE);
  /* 文字列表示 */
  KINGPuts(48,  68, "     ブリーオフ");
  KINGPuts(48, 162, "     1P vs COM");
  KINGPuts(48, 180, "     1P vs 2P");
  KINGPuts(48, 198, "PC-FXGA SAMPLE SOFT");
  /* 文字列中に\353\257 を入れると (C)がでます。全角フォントです。 */
  /* Ｃ６２７２表示オン */ 
  KINGDispOn();
  dispon(bg | spr | bg0);
  /* 割り込み許可 */
  irq_enable();
  
  round = START_ROUND;      /* ラウンドを初期化 */
  
  /* タイトル曲をならす */
  PSGTitle();
  /* モード選択ルーチンを呼ぶ */
  SelectGame();
  
  /* ＰＳＧのフェードアウト */
  PSGFadeOut();
  
  /* ライト初期化 */
  AGLResetLight(AGL_LIGHT0);
  AGLResetLight(AGL_LIGHT1);
  AGLSetLight(AGL_LIGHT0, 0xf000, 0xf000, 0x200, 0x7fff);
  AGLRotateLightY(AGL_LIGHT0, 700);
  AGLRotateLightZ(AGL_LIGHT0, 2700);
  
  /* 画面表示オフ */
  dispoff(bg | spr | bg0);
}

/*
----------------------------------------
  いろいろ初期化
----------------------------------------
*/

LOCAL void
ResetGame()
{
  int i;

  /* ローディング画面作成 */
  dispoff(bg0 | bg | spr);
  KINGScreen(1);
  KINGCls(KING_BG0);
  KINGScroll(KING_BG0, 0, 0);
  KINGKanjiMode(PSET, YUV_WHITE);
  KINGPuts(5, 5, "Font Loading...");
  dispon(bg0);
  /* もしフラグがたっていなければフォント他を読む */
  if (alreadyRead == FALSE) {
    alreadyRead = TRUE;
    /* フォントをフォントバッファに転送 */
    ReadFont("dat/font/spl2.aid");
    NowLoading();
    dispon(bg | spr);
    dispoff(bg0);
    /* テクスチャをバッファへ転送 */
    /*
     * ここと SetDefaultCar() で設定している order[] と
     * select.c の SelectCar() で設定している selorder[] は
     * 密接に関係しているので注意
     */
    /* 車1 テクスチャ 1 */    
    ReadTexture(FALSE, "dat/cartex/ctx5_1.aid", TBANK_P1); 
    /* 車1 テクスチャ 2 */
    ReadTexture(FALSE, "dat/cartex/ctx5_2.aid", TBANK_P1 + 1); 
    SetTextureBank(obj05_g, obj05_g_tindex, TBANK_P1);

    /* 車2 パックトテクスチャ 1 */    
    ReadTexture(FALSE, "dat/cartex/ctx3_1.aid", TBANK_P2); 
    /* 車2 パックトテクスチャ 2 */
    ReadTexture(FALSE, "dat/cartex/ctx3_2.aid", TBANK_P2 + 1); 
    SetTextureBank(obj03_g, obj03_g_tindex, TBANK_P2);
    
    /* 車4 テクスチャ 1 */
    ReadTexture(FALSE, "dat/cartex/ctx4_1.aid", TBANK_P3); 
    SetTextureBank(obj04_g, obj04_g_tindex, TBANK_P3);
    APLSetData();                /* ADPCM データを読み込み KRAM に格納 */
  }
  
  InitPlayer();      /* プレイヤー変数の初期化 */

  /* 材質初期化 */
  for (i = PLAYER_DUMMY; i < PLAYER_MAX; i++) {
    aMaterial[i].ambient  = 0x1000;
    aMaterial[i].diffuse  = 0x3000;
    aMaterial[i].specular = 0x1fff;
    AGLSetMaterial(&aMaterial[i], 1);
  }

  /* ボスコア位置初期化 */
  bosscoreLocate[0][LX] = FarlFloat1015(boss_minmax[MAXX]) * BOSS_BODY_RATIO;
  bosscoreLocate[0][LY] = 0;
  bosscoreLocate[0][LZ] = -FarlFloat1015(boss_minmax[MINY]);
  bosscoreLocate[1][LX] = 0;
  bosscoreLocate[1][LY] = FarlFloat1015(boss_minmax[MAXZ]) * BOSS_BODY_RATIO;
  bosscoreLocate[1][LZ] = -FarlFloat1015(boss_minmax[MINY]);
  bosscoreLocate[2][LX] = FarlFloat1015(boss_minmax[MINX]) * BOSS_BODY_RATIO;
  bosscoreLocate[2][LY] = 0;
  bosscoreLocate[2][LZ] = -FarlFloat1015(boss_minmax[MINY]);
  bosscoreLocate[3][LX] = 0;
  bosscoreLocate[3][LY] = FarlFloat1015(boss_minmax[MINZ]) * BOSS_BODY_RATIO;
  bosscoreLocate[3][LZ] = -FarlFloat1015(boss_minmax[MINY]);
}

/* 
----------------------------------------
  ゲーム開始時の初期化
----------------------------------------
*/
void
InitGame()
{
  int i;

  i = PLAYER1;
  /* 初期位置の決定 */
  Locate[i][LX] = -5.0;
  Locate[i][LY] = 0.0;
  Locate[i][LZ] = 0.0;
  Machine[i].vector.x = 0.0;    /* init X moving vector */
  Machine[i].vector.y = 0.0;    /* init Y moving vector */
  Machine[i].vector.z = 0.0;    /* init Z moving vector */
  Machine[i].colvec.x = 0.0;    /* init X collision vector */
  Machine[i].colvec.y = 0.0;    /* init Y collision vector */
  Machine[i].colvec.z = 0.0;    /* init Z collision vector */
  Machine[i].direct = 900;        /* init degree of direction */
  Machine[i].fbflag = FB_STOP;  /* 停止 */

  i = PLAYER2;
  /* 初期位置の決定 */
  if (round == BOSS_ROUND) {
    Locate[i][LX] = 0.0;
    Locate[i][LZ] = 0.12;
  } else {
    Locate[i][LX] = 5.0;
    Locate[i][LZ] = 0.0;
  }
  Locate[i][LY] = 0.0;
  Machine[i].vector.x = 0.0;    /* init X moving vector */
  Machine[i].vector.y = 0.0;    /* init Y moving vector */
  Machine[i].vector.z = 0.0;    /* init Z moving vector */
  Machine[i].colvec.x = 0.0;    /* init X collision vector */
  Machine[i].colvec.y = 0.0;    /* init Y collision vector */
  Machine[i].colvec.z = 0.0;    /* init Z collision vector */
  Machine[i].direct = 2700;        /* init degree of direction */
  Machine[i].fbflag = FB_STOP;  /* 停止 */

  InitGround(round);                /* 地面関係初期化 */
  InitCollision();                /* 衝突関係初期化 */
  gameTimer = 99;                /* ゲーム時間の設定 */
  whichFall = PLAYER_DUMMY;        /* どちらも落ちていない */

  /* 操作ルーチンの登録・その他の設定 */
  if (playmode == VSCOM) {
    SetDefaultCar(round);        /* round 1 */
    SetMachine(PLAYER1, MT_HUMAN); /* プレイヤーは必ず人間 */
    SetMachine(PLAYER2, round); /* round面目の敵 */
    Machine[PLAYER1].type->color = CarColor[MT_HUMAN];
    Machine[PLAYER2].type->color = CarColor[round];
  } else {
    SelectCar();
    SetMachine(PLAYER1, MT_HUMAN1);
    parfunc[machPlayer1](Machine[PLAYER1].type);
    SetMachine(PLAYER2, MT_HUMAN2);
    parfunc[machPlayer2](Machine[PLAYER2].type);
    PSGFadeOut();
  }
  dispoff(bg0);
  NowLoading();
  dispon(bg | spr);

  /* 地面のテクスチャ読み込み */
  /*
    以前ＣＰＵ対戦だったら床テクスチャーを読む
   */
  if (oldplaymode == VSCOM){
    ReadTexture(FALSE, grname[round - 1], TBANK_GR); 
  }
  dispoff(bg0);
  ReadBG(backname[round - 1]);  /* 背景データの読み込み */
  /* 上記の判定に使うため現在のモードを保存する。*/
  oldplaymode = playmode;
  /* 念のために画面をスワップ */
  ASLSync();
  AGLShot();
  MSLSync();
  /* 背景データの表示 */
  KINGScreen(0);
  KINGCylinder(KING_BG0, 1);
  KINGChangeSize0(DISP_WIDE);
  KINGDispOn();
  dispon(bg | spr | bg0);
}

/*
----------------------------------------
  ゲーム本体
----------------------------------------
*/
LOCAL int
GameMain()
{
  get_pad();                        /* パッドセンス */
  Pad00 = pad00;
  Pad10 = pad10;

  if ((Pad00.KD_TRG & KP_run) || (Pad10.KD_TRG & KP_run)) {
    VSyncUnset();
    PSGSeOff();
    Pause();
    VSyncSet(&TimerDecrement);
  }

  if (round != BOSS_ROUND) {
    if (ObjectMan() != FALSE)        /* 登録ルーチンによる動作パターンの処理 */
      return TRUE;                /* どっちかが落ちた */
  } else {                        /* ボスラウンド時特別処理 */
    if (BossObjectMan() != FALSE)
      return TRUE;                /* プレイヤーが落ちたかボスが破壊された */
  }
  VSyncWait();
  SetGround();                        /* 地面位置・大きさ計算 */
  if (playmode == VSCOM) {        /* 1P vs COM */
    SetCamera(PLAYER1);                /* カメラ設定 */
    /* オブジェクト描画 */
    if (round != BOSS_ROUND) {
      DrawObjects(0, 0, PLAYER2);
      DrawGround();
    } else
      BossDrawObjects();
  } else {                        /* 1P vs 2P */
#ifdef DOUBLEVIEW
    /* PLAYER1の視点を画面上に描画 */
    FarlSetWindowClipReg(0, 0, 255, 119);
    FarlSetWindowScaleReg(128 * SCALE_PERS, 128, -128 * SCALE_PERS, 60);
    SetCamera(PLAYER1);
    DrawObjects(0, 0, PLAYER2);
    DrawGround();
    /* PLAYER2の視点を画面下に描画 */
    FarlSetWindowClipReg(0, 120, 255, 239);
    FarlSetWindowScaleReg(128 * SCALE_PERS, 128, -128 * SCALE_PERS, 120 + 60);
    SetCamera(PLAYER2);
    DrawObjects(0, 0, PLAYER1);
    DrawGround();
#endif
#ifdef BIRDVIEW
    FarlSetWindowClipReg(0, 0, 255, 255);
    FarlSetWindowScaleReg(128 * SCALE_PERS, 128, -128 * SCALE_PERS, 128);
    SetCamera(PLAYER_DUMMY);
    DrawObjects(0, 0, PLAYER1);
    DrawObjects(0, 0, PLAYER2);
    DrawGround();
#endif
  }
  /* プレイヤーごとの処理を呼ぶ */
  Machine[PLAYER1].manFunc(PLAYER1);
  Machine[PLAYER2].manFunc(PLAYER2);
  /* 背景位置の計算 */
  /* 浮動小数点を使った重い計算なので割り込みルーチン外で行う */
  backpos1 
    = (short)(((3600 - Machine[PLAYER1].direct) / 10.0) * DEGPERDOTS);
  backpos2 
    = (short)(((3600 - Machine[PLAYER2].direct) / 10.0) * DEGPERDOTS);
  if (playmode == VSCOM)
    MSLPutDec(gameTimer, TIMER_X, TIMER_Y); /* 残り時間表示 */
  else
    MSLPutDec(gameTimer, TIMER2_X, TIMER2_Y); /* 残り時間表示 */
  {
    static int flag = FALSE;

    if ((Pad00.KD_TRG & KP_2)) {
      flag = TRUE;
      PSGSeOn(SE_ENGINE);
    }
    if (flag == TRUE && !(Pad00.KD_DAT & KP_2)) {
      flag = FALSE;
      PSGSeOn(SE_ENGINE_STOP);
    }
  }
  ASLSync();
  AGLShot();                        /* 描画面交換 */
  MSLSync();

  if (gameTimer <= 0)
    return TRUE;
  return FALSE;
}

/*
========================================
  ラウンド・ゲーム終了判定
========================================
*/
LOCAL void
GameMatch()
{
  if (playmode == VSCOM) {
    if (whichFall == PLAYER1) {
    /* 垂直同期割り込みに登録してある関数を呼ばないようにする */
      VSyncUnset();                
      YouLost();
      GameOver();
    } else {
      if (round != BOSS_ROUND) {
        YouWon();
        dispoff(bg | spr | bg0);
        round++;
        return;
      } else
        PSGSeOff();
      BossBang();                /* ボス破壊 */
    }
  } else {
    WhoWon();                        /* 対戦時の勝利判定 */
  }
  ASLSync();                         /* スプライトを消す */
  AGLShot();
  MSLSync();
  if (round >= ROUND_MAX) {
    /* ボスのテクスチャが書き込まれているので読みなおす */
    ReadTexture(FALSE, "dat/cartex/ctx4_1.aid", TBANK_P3);
    SetTextureBank(obj04_g, obj04_g_tindex, TBANK_P3);
  }
  Opening();
}

/*
========================================
  ゲーム
========================================
*/
void
game()
{
  Opening();
  while (1) {
    InitGame();
    BackScroll1();
    GameStart();
    /* ゲーム開始なのでタイマー減算開始 */
    if (playmode == VSCOM)
      MSLPutDec(gameTimer, TIMER_X, TIMER_Y);
    else
      MSLPutDec(gameTimer, TIMER2_X, TIMER2_Y);
    VSyncWait();
    VSyncSet(&TimerDecrement);
    if (playmode == VSCOM) {
      RasterOn(RASTER_SCROLL1);
    } else {
      RasterOn(RASTER_SCROLL1);
      RasterOn(RASTER_SCROLL2);
    }
    PSGStage(round);
    PSGSeOn(SE_IDLE);
    /* ゲーム開始 */
    while (1)
      if (GameMain())
        break;
    
    GameMatch();    /* 勝敗を判定 */
    VSyncUnset();
    RasterOff(RASTER_SCROLL1);
    RasterOff(RASTER_SCROLL2);
  }
}
/*
----------------------------------------
  タイトル用フォントセットの登録
  int fontset
    fontset: 0 フラットシェーディングモデル
             1 グーローシェーディングモデル
----------------------------------------
*/
LOCAL void
FontSet(int fontset)
{
  switch (fontset) {
    case 0:
      obj[0].geometryTop = (int *)alpha_b_f;
      obj[0].geometryLength = alpha_b_f_length / sizeof(int);
      obj[1].geometryTop = (int *)alpha_u_f;
      obj[1].geometryLength = alpha_u_f_length / sizeof(int);
      obj[2].geometryTop = (int *)alpha_l_f;
      obj[2].geometryLength = alpha_l_f_length / sizeof(int);
      obj[3].geometryTop = (int *)alpha_l_f;
      obj[3].geometryLength = alpha_l_f_length / sizeof(int);
      obj[4].geometryTop = (int *)alpha_y_f;
      obj[4].geometryLength = alpha_y_f_length / sizeof(int);
      obj[5].geometryTop = (int *)alpha_o_f;
      obj[5].geometryLength = alpha_o_f_length / sizeof(int);
      obj[6].geometryTop = (int *)alpha_f_f;
      obj[6].geometryLength = alpha_f_f_length / sizeof(int);
      obj[7].geometryTop = (int *)alpha_f_f;
      obj[7].geometryLength = alpha_f_f_length / sizeof(int);
      break;
    case 1:
      obj[0].geometryTop = (int *)alpha_b_g;
      obj[0].geometryLength = alpha_b_g_length / sizeof(int);
      obj[1].geometryTop = (int *)alpha_u_g;
      obj[1].geometryLength = alpha_u_g_length / sizeof(int);
      obj[2].geometryTop = (int *)alpha_l_g;
      obj[2].geometryLength = alpha_l_g_length / sizeof(int);
      obj[3].geometryTop = (int *)alpha_l_g;
      obj[3].geometryLength = alpha_l_g_length / sizeof(int);
      obj[4].geometryTop = (int *)alpha_y_g;
      obj[4].geometryLength = alpha_y_g_length / sizeof(int);
      obj[5].geometryTop = (int *)alpha_o_g;
      obj[5].geometryLength = alpha_o_g_length / sizeof(int);
      obj[6].geometryTop = (int *)alpha_f_g;
      obj[6].geometryLength = alpha_f_g_length / sizeof(int);
      obj[7].geometryTop = (int *)alpha_f_g;
      obj[7].geometryLength = alpha_f_g_length / sizeof(int);
      break;
  }
}
/*
----------------------------------------
  タイトル用フォントセットの初期化
----------------------------------------
*/
#define FLAT_FONT    0
#define GOURAUD_FONT 1
LOCAL void 
FontInit()
{
  int i;

  /* 視点の設定 */
  AGLResetCamera();
  AGLTranslateCamera(0, -0x10, 0);
  AGLRotateCameraX(900);
  AGLPerspectiveCamera(0xffc0 * SCALE_PERS);
  AGLZoomCamera(0x100, 0x100, 0x100);
  /* ライト初期化 */
  AGLResetLight(AGL_LIGHT0);
  AGLResetLight(AGL_LIGHT1);
  AGLSetLight(AGL_LIGHT0, 0xf000, 0xf000, 0x200, 0x6000);
  AGLRotateLightY(AGL_LIGHT0, 700);
  AGLRotateLightZ(AGL_LIGHT0, 3300);
  FontSet( FLAT_FONT );
  /* 各種変数初期化 */
  iRotateAngle = 0;
  iFontColor = 1;
  BullyMaterial.ambient = 0x1000;
  BullyMaterial.diffuse = 0x6000;
  BullyMaterial.specular = 0x7fff;
  for (i = 0; i < STRLENGTH; i++ ) {
    BullySize[i] = 0x60;
    BullyZSize[i] = 0x60;
    BullyYPos[i] = 0.35;
    BullyXRot[i] = 0;
    obj[i].material = &BullyMaterial;
  }
  AGLSetMaterial(&BullyMaterial, 1);
}

/*
----------------------------------------
  タイトルフォントアクション
----------------------------------------
*/
LOCAL void
FontMove()
{
  int i;
  static int fontset = FLAT_FONT;

  /* 文字数分のループ */
  for (i = 0; i < STRLENGTH; i++) {
    AGLResetObj(&obj[i]);
    /* デフォルトカラー設定 */    
    FarlSetDefColorReg(0x1401 + i + iFontColor);
    /* スケール決定 */
    AGLScaleObj(&obj[i], 0x60, BullySize[i], BullyZSize[i]);
    /* 向き決定 */
    AGLRotateObjX(&obj[i], 900);
    AGLRotateObjY(&obj[i], 0);
    AGLRotateObjZ(&obj[i], BullyXRot[i]);
    /* 位置決定 */
    AGLTranslateObj(&obj[i],
                    FarlFix187(BullyXPos[i]),
                    FarlFix187(0.06),  /* 0.06 */
                    FarlFix187(BullyYPos[i])
                    );
    /* 描画 */
    AGLFixPutObj(&obj[i]);
  }
  /* 文字数分のループ */
  for (i = 0; i < STRLENGTH; i++) {
    /* タイミングその１ 落ちる */
    if (iRotateAngle >= (20 * i) && iRotateAngle < (360 + 20 * i)) {
      BullyYPos[i] -= 0.01;
      BullyXRot[i] += 50; /* ５°毎まわる */
    }
    /* タイミングその２ あがる */
    if (iRotateAngle >= (360 + 20 * i) && iRotateAngle < (600 + 20 * i)) {
      BullyYPos[i] += 0.01;
      BullyXRot[i] += 50; /* ５°毎まわる */
    }
    /* タイミングその３ また落ちる */
    if (iRotateAngle >= (600 + 20 * i) && iRotateAngle < (780 + 20 * i)) {
      BullyYPos[i] -= 0.01;
      BullyXRot[i] += 50; /* ５°毎まわる */
    }
    /* タイミングその４ その場で逆回転 */
    if (iRotateAngle >= (1600 + 20 * i) && iRotateAngle <= (1780 + 20 * i)) {
      BullyXRot[i] -= 200; /* ２０°毎まわる */
      /* サイズを変える （伸びる） */
      BullySize[i] += costbl[(iRotateAngle - 1600 - 20 * i)] * 5;
      BullyZSize[i] += costbl[(iRotateAngle - 1600 - 20 * i)] * 5;
    }
    /* タイミングその５ 縮む */
    if (iRotateAngle >= (1790 + 20 * i) && iRotateAngle <= (1970 + 20 * i)) {
      /* サイズを変える （縮む） */
      BullySize[i] -= costbl[(iRotateAngle - 1790 - 20 * i)] * 5;
      BullyZSize[i] -= costbl[(iRotateAngle - 1790 - 20 * i)] * 5;
    }
    /* タイミングその６ 上に帰る */
    if (iRotateAngle >= (2000 + 20 * i) && iRotateAngle < (2300 + 20 * i)) {
      BullyYPos[i] += 0.01;
      BullyXRot[i] += 50;
    }
    /* 上が押されたら巨大化 */
    if (pad10.KD_DAT & KP_up)
      BullySize[i] = 0x100;
    /* 下が押されたら縮小 */
    if (pad10.KD_DAT & KP_down)
      BullySize[i] = 0x20;
    /* 左右が押されたら元に戻る */
    if (pad10.KD_DAT & KP_left || pad10.KD_DAT & KP_right)
      BullySize[i] = 0x60;
  }
  /* その場でまわるときに色を変える */
  if (iRotateAngle == 1780) {
    iFontColor = (iFontColor + 1) & 0x07;
  }
  /* タイミングカウンタの増加 */
  iRotateAngle += 10;
  /* 最後だったら初期化する */
  if (iRotateAngle > 2500) {
    iRotateAngle = 0;
    for (i = 0; i < STRLENGTH; i++ ) {
      BullyYPos[i] = 0.35;
      BullyXRot[i] = 0;
    }
  }
  /* セレクトが押されたら色を変える */
  if (pad10.KD_TRG & KP_select)
    iFontColor = (iFontColor + 1) & 0x07;
  /* RUNが押されたらフォントを変える */
  if (pad10.KD_TRG & KP_run) {
    if (fontset == FLAT_FONT)
      fontset = GOURAUD_FONT;
    else
      fontset = FLAT_FONT;
    FontSet(fontset);
  }
}


/*
========================================
  自分の動きにあわせて背景をスクロールさせる
  引き数：なし
  戻り値：なし
========================================
*/
void
BackScroll1(void)
{
  KINGScroll(KING_BG0, backpos1 & 0x1ff, RASTER_SCROLL1);
}

void
BackScroll2(void)
{
  KINGScroll(KING_BG0, backpos2 & 0x1ff, RASTER_SCROLL2);
}
